package com.itheima.reggie.filter;

import com.alibaba.fastjson.JSON;
import com.itheima.reggie.common.BaseContext;
import com.itheima.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/*
  这种 filter  web组件 原本是tomcat管理的
    现在它需要被spring 发现！！
        过滤器 不写拦截规则 代表 拦截所有请求。
           (静态资源 动态资源都拦截)
     我们这个过滤器如何被spring管理呢，需要在启动类这里加一个注解
       开启 web组件注解的扫描@ServletComponentScan
 */
@WebFilter(filterName = "LoginCheckFilter")
@Slf4j
public class LoginCheckFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

        log.info("当前的请求到达这个过滤器了，说明被过滤器拦截住了");
        // 因为我们要 使用 儿子特有的功能 所以需要向下转型
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)resp;
        //  拦截住请求了，怎么能知道请求路径是什么？
        String requestURI = request.getRequestURI();
        log.info("拦截的路径URI："+requestURI);
        // 拦截策略
        // 1：先判断这个路径 是不是需要进行 登录访问
        //  不需要登录访问的路径 就放行  需要的不放行继续
        boolean isAuth = checkAuthUrl(requestURI); //检查访问的路径是不是白名单
        //是白名单  就不用登录访问 直接放行
        if(isAuth){//true
            log.info(requestURI+" 是白名单，不需要登录访问，放行");
            chain.doFilter(request,response);//进行放行
            return;// 不用往下了  必须写
        }

        System.out.println("过滤器路径"+requestURI+"当前的线程id:"+Thread.currentThread().getId());

        // 2: 继续判断 用户是不是登陆了
        // 登录之后 会把id存到 session域中
        HttpSession session = request.getSession();
        // 能在session中找到id 说明 登录了 找不到 没登录
        Object empId = session.getAttribute("employee");
        if(empId!=null){//找到了 登录过了
            log.info(requestURI+" 已经登陆了，放行");
            //  登陆过了 就把 empId 存到 ThreadLocal对象中
//            BaseContext.getThreadLocal().set((Long) empId);//通过指定的ThreadLocal存储
            BaseContext.setCurrentId((Long) empId);// 外界根本不知道我底层用了什么
            chain.doFilter(request,response);//进行放行
            return;// 不用往下了  必须写
        }
        // 手机端 登录校验 能在session中找到id 说明 登录了 找不到 没登录
        Object userId = session.getAttribute("user");
        if(userId!=null){//找到了 登录过了
            log.info(requestURI+" 手机端已经登陆了，放行");
            BaseContext.setCurrentId((Long) userId);
            chain.doFilter(request,response);//进行放行
            return;// 不用往下了  必须写
        }

        // 没有登录 告知前端页面  NOTLOGIN  R.error("NOTLOGIN")
//        R.error("NOTLOGIN");得把这数据告诉前端
        // 说明没登录 需要登录访问
        log.info(requestURI+" 既不是白名单，又没登录，先去登录");
        //   R.error("NOTLOGIN")  对象怎么转换成json
        String json = JSON.toJSONString(R.error("NOTLOGIN"));
        // 响应的内容 不能直接响应对  响应的json格式数据
        response.getWriter().write(json);
    }

    /**
     *   有经验的人 就设计方法了
     *   判断一下 传递过来的  requestURI 是不是白名单 路径
     * @param requestURI
     * @return
     */
    public boolean checkAuthUrl(String requestURI) {
    // 拿 requestURI  跟数组中的路径规则 进行匹配
     //  判断一个路径 符合不符合某种规则  有没有专门的判断规则的对象呢？
        // 如果有  是不是就不用自己 费脑筋去想了。。。。
        // Spring中 有个路径匹配器 AntPathMatcher
        //   功能  boolean match(规则,路径) 判断路径是不是符合规则
        AntPathMatcher matcher = new AntPathMatcher();//新学的
        for (String url : authUrl) {//遍历  白名单规则
            //url是白名单规则  requestURI 判断的路径
//            boolean match = matcher.match(url, requestURI);
            if(matcher.match(url, requestURI)){//符合规则
                return true;
            }
        }
        return false;
    }

    // 不需要登录访问的 路径 是一个还是多个呢？
    //  /backend/page/login/login.html
    //  /front/page/login.html
    //  /employee/login      有经验的程序员 会把这个多个不需要登录访问的路径 设计为一个数组
    //  起名叫 白名单
    private String[] authUrl= new String[]{
            "/employee/login",
            "/employee/logout",
            "/backend/**",
            "/front/**",
            "/common/upload",
            "/common/download",
            "/user/login",
            "/user/sendMsg",
            "/doc.html",
            "/webjars/**",
            "/swagger-resources",
            "/v2/api-docs"
    };// 数组里面 其实写的是路径的规则


    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
    }

}
